package com.hotspot.chartview.view;

import java.util.ArrayList;
import java.util.List;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;

import com.hotspot.chartview.R;
import com.hotspot.chartview.model.FunnelChartData;

/**
 * 漏斗形报表
 * 
 * @author BaiYuliang
 */
public class FunnelChart extends View implements AnimatorUpdateListener {

    /**
     * 从xml中读取到的属性
     */
    private int mPathColor; // Path的颜色
    private int mLineColor; // 线的颜色
    private int mTitleTextColor; // 标题的颜色
    private int mTitleTextSize; // 标题的大小

    /**
     * 画笔
     */
    private Paint mPaintPath; // 画Path使用的画笔
    private Paint mPaintLine; // 画线使用的画笔
    private Paint mPaintTitleText; // 画标题用的画笔

    private float mDeltaX;
    private float mDeltaY;
    private float mTitleDeltaX;
    private int mFunnelViewWidth;
    private int mFunnelItemHeight;
    private float mDataMaxWidth;
    private List<FunnelChartData> mFunnelChartDatas;

    /**
     * 动画
     */
    private float mPhaseX = 1f;
    private float mPhaseY = 1f;
    private ObjectAnimator mAnimatorX;
    private ObjectAnimator mAnimatorY;

    public FunnelChart(Context context) {
        this(context, null, 0);
    }

    public FunnelChart(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FunnelChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (attrs != null) {
            Resources resources = getResources();
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FunnelChart);
            mPathColor = typedArray.getColor(R.styleable.FunnelChart_path_color,
                    resources.getColor(R.color.funnel_chart_path_color_default));
            mLineColor = typedArray.getColor(R.styleable.FunnelChart_line_color,
                    resources.getColor(R.color.funnel_chart_line_color_default));
            mTitleTextColor = typedArray.getColor(R.styleable.FunnelChart_title_text_color,
                    resources.getColor(R.color.funnel_chart_title_color_default));
            mTitleTextSize = typedArray.getDimensionPixelSize(
                    R.styleable.FunnelChart_title_text_size, 15);
            typedArray.recycle();
        }

        init(context);
    }

    /**
     * 初始化参数
     * 
     * @param context
     *            上下文
     */
    private void init(Context context) {
        mFunnelChartDatas = new ArrayList<FunnelChartData>();

        /**
         * 创建画Path使用的画笔
         */
        mPaintPath = new Paint();
        mPaintPath.setColor(mPathColor);
        mPaintPath.setStrokeWidth(1);
        mPaintPath.setAntiAlias(true);
        mPaintPath.setStyle(Paint.Style.FILL);

        /**
         * 创建画线使用的画笔
         */
        mPaintLine = new Paint();
        mPaintLine.setColor(mLineColor);
        mPaintLine.setStrokeWidth(3);
        mPaintLine.setAntiAlias(true);
        mPaintLine.setStyle(Paint.Style.STROKE);
        PathEffect pathEffect = new DashPathEffect(new float[] { 12, 12 }, 0);
        mPaintLine.setPathEffect(pathEffect);

        /**
         * 创建画标题用的画笔
         */
        mPaintTitleText = new Paint();
        mPaintTitleText.setColor(mTitleTextColor);
        mPaintTitleText.setTextSize(convertDpToPixel(mTitleTextSize));
        mPaintTitleText.setStrokeWidth(1);
        mPaintTitleText.setAntiAlias(true);
    }

    /**
     * 将dip转换为pixel
     * 
     * @param dp
     *            dip
     * @return 将dip转换为pixel
     */
    private float convertDpToPixel(float dp) {
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;
    }

    /**
     * 初始化单元格的大小和位置
     */
    private void initCellSizeAndPosition() {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        mTitleDeltaX = mPaintTitleText.getTextSize();
        mDeltaX = getPaddingLeft();
        mDeltaY = getPaddingTop() + mPaintTitleText.getTextSize();

        if (mFunnelChartDatas.size() > 1) {
            mFunnelViewWidth = width * 2 / 3;
            mFunnelItemHeight = (int) (height - mDeltaY * 2) / (mFunnelChartDatas.size() - 1);
        }

        /**
         * 内容的最大值
         */
        for (FunnelChartData funnelChartData : mFunnelChartDatas) {
            if (funnelChartData.height >= mDataMaxWidth) {
                mDataMaxWidth = funnelChartData.height;
            }
        }
    }

    /**
     * 画漏斗
     * 
     * @param canvas
     *            画布
     */
    private void drawFunnel(Canvas canvas) {
        canvas.save();
        canvas.translate(mDeltaX, mDeltaY);
        Path path = new Path();
        path.moveTo(0, 0);
        for (int i = 0; i < mFunnelChartDatas.size(); i++) {
            FunnelChartData funnelChartData = mFunnelChartDatas.get(i);
            path.lineTo(mPhaseX * funnelChartData.height * mFunnelViewWidth / mDataMaxWidth,
                    mFunnelItemHeight * i);
        }
        path.lineTo(0, mFunnelItemHeight * (mFunnelChartDatas.size() - 1));
        path.close();
        canvas.drawPath(path, mPaintPath);
        canvas.restore();
    }

    /**
     * 画线
     * 
     * @param canvas
     *            画布
     */
    private void drawLines(Canvas canvas) {
        canvas.save();
        canvas.translate(mDeltaX, mDeltaY);
        for (int i = 0; i < mFunnelChartDatas.size(); i++) {
            Path path = new Path();
            path.moveTo(0, mFunnelItemHeight * i);
            path.lineTo(mFunnelViewWidth + mTitleDeltaX, mFunnelItemHeight * i);
            path.close();
            canvas.drawPath(path, mPaintLine);
        }
        canvas.restore();
    }

    /**
     * 画标题
     * 
     * @param canvas
     *            画布
     */
    private void drawTitles(Canvas canvas) {
        canvas.save();
        canvas.translate(mDeltaX + mFunnelViewWidth + mTitleDeltaX * 2, mDeltaY / 2);
        int top = 0;
        for (int i = 0; i < mFunnelChartDatas.size(); i++) {
            String title = mFunnelChartDatas.get(i).title;
            Rect targetRect = new Rect(0, top, (int) mPaintTitleText.measureText(title), top
                    + (int) mPaintTitleText.getTextSize());
            FontMetricsInt fontMetrics = mPaintTitleText.getFontMetricsInt();
            int baseLine = targetRect.top
                    + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top)
                    / 2 - fontMetrics.top;

            canvas.drawText(title, 0, baseLine, mPaintTitleText);
            top += mFunnelItemHeight;
        }
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initCellSizeAndPosition(); // 初始化单元格大小和初始位置
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawFunnel(canvas); // 画漏斗
        drawLines(canvas); // 画线
        drawTitles(canvas); // 画标题
    }

    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        invalidate();
    }

    /**
     * phaseX的setter方法，与ObjectAnimator配合使用
     * 
     * @param phaseX
     *            X轴动画完执行进度
     */
    public void setPhaseX(float phaseX) {
        mPhaseX = phaseX;
    }

    /**
     * phaseY的setter方法，与ObjectAnimator配合使用
     * 
     * @param phaseY
     *            Y轴动画执行进度
     */
    public void setPhaseY(float phaseY) {
        mPhaseY = phaseY;
    }

    /**
     * X轴执行动画
     * 
     * @param durationMillis
     *            执行动画的时间
     */
    public void animateX(int durationMillis) {
        mAnimatorX = ObjectAnimator.ofFloat(this, "phaseX", 0f, 1f);
        mAnimatorX.setDuration(durationMillis);
        mAnimatorX.addUpdateListener(this);
        mAnimatorX.start();
    }

    /**
     * Y轴执行动画
     * 
     * @param durationMillis
     *            执行动画的时间
     */
    public void animateY(int durationMillis) {
        mAnimatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
        mAnimatorY.setDuration(durationMillis);
        mAnimatorY.addUpdateListener(this);
        mAnimatorY.start();
    }

    /**
     * 填充数据
     * 
     * @param funnelChartDatas
     *            报表数据
     */
    public void setFunnelChartData(List<FunnelChartData> funnelChartDatas) {
        mFunnelChartDatas.clear();
        if (funnelChartDatas != null && funnelChartDatas.size() > 0) {
            mFunnelChartDatas.addAll(funnelChartDatas);
        }
        initCellSizeAndPosition();
        invalidate();
    }

}
